package simulation;

import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.List;
import view.Canvas;
import forces.Force;


/**
 * The Model has the responsibility of updating the masses, springs, and forces
 * in the simulation, as well as special features associated with key presses.
 * 
 */
public class Model {
    private static final int SIZE_CHANGE = 10;
    // bounds and input for game
    private Canvas myView;
    // simulation state
    private List<Mass> myMasses;
    private List<Spring> mySprings;
    private List<Force> myForces;
    private MouseDragger myMouseDragger;
    private ForceToggler myForceToggler;
    private int myAreaChange;

    /**
     * Create a game of the given size with the given display for its shapes.
     */
    public Model (Canvas canvas) {
        myView = canvas;
        myMasses = new ArrayList<Mass>();
        mySprings = new ArrayList<Spring>();
        myForces = new ArrayList<Force>();
        myMouseDragger = new MouseDragger();
        myForceToggler = new ForceToggler();
        myAreaChange = 0;
    }

    /**
     * Draw all elements of the simulation.
     */
    public void paint (Graphics2D pen) {
        for (Spring s : mySprings) {
            s.paint(pen);
        }
        for (Mass m : myMasses) {
            m.paint(pen);
        }
        myMouseDragger.paint(pen);
    }

    /**
     * Update simulation for this moment, given the time since the last moment.
     */
    public void update (double elapsedTime) {
        Dimension bounds = myView.getSize();

        checkAssemblies();
        changeSize();
        myForceToggler.update(myForces, myView.getLastKeyPressed());
        myMouseDragger.update(elapsedTime, bounds, myView.getLastMousePosition(), myMasses);

        for (Spring s : mySprings) {
            s.update(elapsedTime, bounds);
        }

        for (Force f : myForces) {
            f.update(myMasses);
        }

        for (Mass mass : myMasses) {
            mass.changeSize(myAreaChange);
            mass.update(elapsedTime, bounds);
        }

        // need this here, otherwise does not work.
        myView.resetKey();
    }

    /**
     * Creates or destroys assemblies based on key press.
     */
    private void checkAssemblies () {
        int key = myView.getLastKeyPressed();
        if (key == KeyEvent.VK_N) {
            myView.loadModel("assembly");
        }
        else if (key == KeyEvent.VK_C) {
            myMasses.clear();
            mySprings.clear();
        }
    }

    /**
     * Changes the size of the area for the simulation.
     */
    private void changeSize () {
        int key = myView.getLastKeyPressed();
        if (key == KeyEvent.VK_UP) {
            myAreaChange += SIZE_CHANGE;
        }
        if (key == KeyEvent.VK_DOWN) {
            myAreaChange -= SIZE_CHANGE;
        }
    }

    /**
     * Add given mass to this simulation.
     */
    public void add (Mass mass) {
        myMasses.add(mass);
    }

    /**
     * Add given spring to this simulation.
     */
    public void add (Spring spring) {
        mySprings.add(spring);
    }

    /**
     * Add a given force to this simulation.
     */
    public void add (Force force) {
        myForces.add(force);
    }
}
